---@module uart485
--- 模块功能：串口收发
-- @author flamebox
-- @license MIT
-- @copyright openLuat
-- @release 2019.2.18
require "utils"
require "pm"
require "config"
require "tool"
require "uart485"
-- require "serviceConfig"
require "nvm"
require "common"
require "aLiCMD"

module(..., package.seeall)
TEST_MODE = false
-------------------------------------------- 配置串口 --------------------------------------------

-- 保持系统处于唤醒状态，不会休眠
pm.wake("485_uart")
-- 485芯片相关设置
pmd.ldoset(15, pmd.LDO_VMMC)
local DIR_485 = pins.setup(pio.P0_24, 0)
local cmd_buf
-- 串口ID,串口读缓冲区
local uart_id = 3
-- 串口参数, 固定对应液位仪表
local uart_baud = 2400
local uart_data_bits = 8
local uart_stop_bits = uart.STOP_1
local uart_parity = uart.PAR_NONE
local uart_master = 1 -- 访问的控制器的485地址

local dev_type = nvm.get("DEV_TYPE")
local dev_addr = nvm.get("SLAVE_ID")
local dev_baud = nvm.get("BAUD")

----将1个数字转换成高8位和低8位的2个字节
-- local function intToChar(num)
--    local result = {}
--    result[1] = bit.rshift(num, 8)
--    result[2] = bit.band(num, 0x00ff)
--    return result
-- end

-- modbus 命令返回校验处理
local function checkmodbus(data)
    if string.len(data) < 3 then
        log.warn("MODBUS", "Data is too short")
        return false
    end

    -- 校验读回来的包是否整个crc正确
    if pack.pack('<H', crypto.crc16("MODBUS", string.sub(data, 1, -3))):toHex() ~=
        string.sub(data, -2):toHex() then
        log.warn("MODBUS", "CRC error " .. string.toHex(data))
        return false
    end

    return true
end

--[[
函数名：read
功能  ：读取串口接收到的数据
参数  ：无
返回值：无
]]
local function read()
    local data = ""
    cmd_buf = ""
    -- 底层core中，串口收到数据时：
    -- 如果接收缓冲区为空，则会以中断方式通知Lua脚本收到了新数据；
    -- 如果接收缓冲器不为空，则不会通知Lua脚本
    -- 所以Lua脚本中收到中断读串口数据时，每次都要把接收缓冲区中的数据全部读出，这样才能保证底层core中的新数据中断上来，此read函数中的while语句中就保证了这一点
    while true do
        data = uart.read(uart_id, "*l")
        cmd_buf = cmd_buf .. data
        if not data or string.len(data) == 0 then break end
    end
    -- 打开下面的打印会耗时
    log.info("Uart get ", "msg: " .. string.toHex(cmd_buf))
    if checkmodbus(cmd_buf) == true then
        sys.publish("MY_UART_REC_MODBUS", cmd_buf)

    end

end

--[[
函数名：read
功能  ：读取串口接收到的数据
参数  ：无
返回值：无
]]
local function modbus_read()
    local dev_addr = nvm.get("SLAVE_ID")
    if dev_addr == "99" then
        modbus_data = string.char(0x01, 0x03, 0x00, 0x01, 0x00, 0x01)
    else
        modbus_data = string.fromHex(dev_addr .. "03 00 00 00 08")
    end
    -- ,使用出厂默认地址1
    -- local modbus_data = string.char(0x01, 0x03, 0x00, 0x02, 0x00, 0x01)
    -- 计算CRC
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart send ",
             "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    local cacheData = ""
    while true do
        local s = uart.read(uart_id, 1)
        -- local s = uart.read(uart_id, "*l")
        if s == "" then

            -- if not sys.waitUntil("UART2_RECEIVE", 35000 / uart_baud) then
            if not sys.waitUntil("UART2_RECEIVE", 50) then
                -- 设置的延时时间越短，误差越大
                if cacheData:len() > 0 then

                    if cacheData == "test#" then -- 做为被测试从机时，收到测试命令就要应答
                        uart.write(uart_id, "test_ok")
                    elseif cacheData == "test_ok" then -- 做为测试主机时，收到应答，表示测试ok
                        sys.publish("UART_TEST2_OK")
                    end

                    -- local a, _ = string.toHex(cacheData)
                    -- 打开下面的打印会耗时
                    -- log.info("Uart 3 get ", "msg: " .. string.toHex(cacheData))

                    --  如开启透传模式
                    if nvm.get("TRANSMIT_MODE") then

                        -- aLiCMD.eventPost(string.toHex(cacheData))
                        -- log.info("RES3",
                        --          string.sub(string.toHex(cacheData), 1, 2))
                        if string.find(string.toHex(cacheData), string.toHex(
                                           modbus_data .. modbus_crc_data)) ~=
                            nil then
                            log.info("Uart 3 get ",
                                     "msg: " .. string.toHex(cacheData))

                            local res = uart485.sendUart3(modbus_data .. modbus_crc_data)
                            if res ~= false then
                                uart.write(uart_id, res)
                                log.info("Uart 3 write ",
                                         "msg: " .. string.toHex(res))

                            end
                        elseif string.sub(string.toHex(cacheData), 1, 2) ==
                            dev_addr and checkmodbus(cacheData) then
                            log.info("Uart 3 get ",
                                     "msg: " .. string.toHex(cacheData))

                            local res = uart485.sendUart3(cacheData)
                            if res ~= false then
                                uart.write(uart_id, res)
                                log.info("Uart 3 write ",
                                         "msg: " .. string.toHex(res))

                            end
                        end
                    end
                    cacheData = ""
                end
                sys.wait(5) -- 这里一定要延时，否则会死机
            end
        else
            cacheData = cacheData .. s
        end

    end
end

if dev_baud == 9999 then
    -- 串口1为rs485
    if dev_type == "TLD" or dev_type == "TLD2" or dev_type == "FGSG" or dev_type ==
        "9600ZF" or dev_type == "JCIOT" or dev_type == "YFKS" or dev_type ==
        "SHYH" or dev_type == "SHYHC8" or dev_type == "DNQ" or dev_type ==
        "TCPW" or dev_type == "XK3101" then
        uart_baud = 9600
    elseif dev_type == "4800ZF" or dev_type == "XK3168" then
        uart_baud = 4800
    elseif dev_type == "NM" then
        uart_baud = 2400
    end
else
    uart_baud = dev_baud
end

-- 设置串口
uart.setup(uart_id, uart_baud, uart_data_bits, uart_parity, uart_stop_bits, nil,
           1) -- 最后参数为1 下面的set_rs485_oe才会作用
uart.set_rs485_oe(uart_id, pio.P0_24, 1, 1, 1)

-- uart.on(uart_id, "receive", read)

uart.on(uart_id, "receive", function() sys.publish("UART2_RECEIVE") end)

-- modbus_data = string.char(0x01,0x03, 0x00, 0x01, 0x00, 0x0C)
-- 发送modbus 指令
function modbusSend(modbus_data)
    local modbus_crc_value = crypto.crc16("MODBUS", modbus_data)
    local modbus_crc_data = pack.pack('<H', modbus_crc_value)
    log.info("Uart 3 send ",
             "msg: " .. string.toHex(modbus_data .. modbus_crc_data))
    uart.write(uart_id, modbus_data .. modbus_crc_data)
end

-- 发送测试命令
function sendTest()
    uart.write(uart_id, "test#")
    local result = sys.waitUntil("UART_TEST2_OK", 3000)
    if result == false then
        log.info("UART_TEST", "Recv test resp timeout!")
    else
        log.info("UART_TEST", "Recv test ok!")
    end
    return result
end

-- 启动串口数据接收任务
sys.taskInit(modbus_read)

